package com.esdk.utils;

import com.alibaba.fastjson.JSONObject;
import com.esdk.esdk;
import com.esdk.exception.SdkRuntimeException;
import com.esdk.interfaces.Callback;
import com.esdk.interfaces.Func;
import com.esdk.interfaces.FuncNoArg;
import com.esdk.interfaces.Runner;
import lombok.SneakyThrows;
import org.nutz.lang.random.R;

import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.*;
import java.util.stream.Stream;

public class EasyFunc {

    /**
     * 可迭代对象非空遍历执行
     */
    public static <T> void FOR(Iterable<T> iterable, Callback<T> action) {
        if(iterable == null) return;
        for (T t : iterable) {
            action.invoke(t);
        }
    }

    /**
     * 可选链
     * 类似于js的obj?.key?.subKey的使用方式，如果抛异常返回默认值或null
     * */
    public static <R> R GET(FuncNoArg<R> fn, R... others){
        try{
            return fn.invoke();
        }catch(NullPointerException | IndexOutOfBoundsException | NoSuchElementException e){
            return esdk.obj.or(others);
        }catch(Exception e){
            throw esdk.tool.wrapThrowble(e);
        }
    }

    /**
     * 类似于js的obj?.key?.setValid(anyObj)的使用方式，不需要返回值
     * */
    public static void SET(Runner runner){
        try{
            runner.run();
        }catch(NullPointerException | IndexOutOfBoundsException | NoSuchElementException e){
        }catch(Exception e){
            throw esdk.tool.wrapThrowble(e);
        }
    }

    public static <R> R safeRun(FuncNoArg<R> fn, R defVal, boolean printEx){
        try{
            return esdk.obj.or(fn.invoke(), defVal);
        }catch(Exception e){
            if(printEx) esdk.error(e);
            return defVal;
        }
    }

    public static <R> R safeRun(FuncNoArg<R> fn, boolean printEx){
        try{
            return fn.invoke();
        }catch(Exception e){
            if(printEx) esdk.error(e);
            return null;
        }
    }

    public static <R> R safeRun(FuncNoArg<R> fn, R defVal){
        try{
            return esdk.obj.or(fn.invoke(), defVal);
        }catch(Exception e){
            return defVal;
        }
    }
    public static <R> R safeRun(FuncNoArg<R> fn){
        try{
            return fn.invoke();
        }catch(Exception e){
            return null;
        }
    }
    public static void safeRun(Runner fn, boolean printEx){
        try{
            fn.run();
        }catch(Exception e){
            if(printEx) esdk.error(e);
        }
    }
    public static void safeRun(Runner fn){
        safeRun(fn, false);
    }


    public static void IF(boolean ifVal,Runner thenCB){
        try{
            if(ifVal)
                thenCB.run();
        }catch(Exception e){
            throw esdk.tool.wrapThrowble(e);
        }
    }

    public static void IF(boolean ifVal,Runner thenCB,Runner elseCB){
        try{
            if(ifVal)
                thenCB.run();
            else if(elseCB!=null)
                elseCB.run();
        }catch(Exception e){
            throw esdk.tool.wrapThrowble(e);
        }
    }

    public static <T,R> Function<T,R> asFunction(Func<T,R> func){
        return (p) -> {
          try{
            return func.invoke(p);
          }catch(Exception e){
            throw esdk.tool.wrapThrowble(e);
          }
        };
    }
    public static <R> Supplier<R> asSupplier(FuncNoArg<R> func){
        return () -> {
            try{
                return func.invoke();
            }catch(Exception e){
                throw esdk.tool.wrapThrowble(e);
            }
        };
    }
    public static <P> Consumer<P> asConsumer(Callback<P> func){
        return (p) -> {
            try{
                func.invoke(p);
            }catch(Exception e){
                throw esdk.tool.wrapThrowble(e);
            }
        };
    }
    public static <P> Predicate<P> asPredicate(Func<P,Boolean> func){
        return (p) -> {
            try{
                return func.invoke(p);
            }catch(Exception e){
                throw esdk.tool.wrapThrowble(e);
            }
        };
    }

    public interface SafeBiFunction<P1,P2,R>{
        R invoke(P1 p1,P2 p2) throws Exception;
    }
    public static <P1, P2, R> BiFunction<P1,P2,R> asBiFunction(SafeBiFunction<P1,P2,R> func){
        return (p1, p2) -> {
            try{
                return func.invoke(p1,p2);
            }catch(Exception e){
                throw esdk.tool.wrapThrowble(e);
            }
        };
    }
    public static <P1, P2, R> Function<P1,R> asFunction(SafeBiFunction<P1,P2,R> func, P2 val){
        return (p1) -> {
            try{
                return func.invoke(p1,val);
            }catch(Exception e){
                throw esdk.tool.wrapThrowble(e);
            }
        };
    }


    public interface SafeBiPredicate<P1,P2>{
        Boolean invoke(P1 p1,P2 p2) throws Exception;
    }
    public static <P1, P2> BiPredicate<P1,P2> asBiPredicate(SafeBiPredicate<P1,P2> func){
        return (p1, p2) -> {
            try{
                return func.invoke(p1,p2);
            }catch(Exception e){
                throw esdk.tool.wrapThrowble(e);
            }
        };
    }
    public static <P1, P2> Predicate<P1> asPredicate(SafeBiPredicate<P1,P2> func, P2 val){
        return (p1) -> {
            try{
                return func.invoke(p1,val);
            }catch(Exception e){
                throw esdk.tool.wrapThrowble(e);
            }
        };
    }


    public interface SafeBiConsumer<P1,P2>{
        void invoke(P1 p1,P2 p2) throws Exception;
    }
    public static <P1, P2> BiConsumer<P1,P2> asBiConsumer(SafeBiConsumer<P1,P2> func){
        return (p1, p2) -> {
            try{
                func.invoke(p1,p2);
            }catch(Exception e){
                throw esdk.tool.wrapThrowble(e);
            }
        };
    }
    public static <P1, P2> Consumer<P1> asConsumer(SafeBiConsumer<P1,P2> func, P2 val){
        return (p1) -> {
            try{
                func.invoke(p1,val);
            }catch(Exception e){
                throw esdk.tool.wrapThrowble(e);
            }
        };
    }

    @SneakyThrows
    public static <T> List<T> pageData(Callback<Integer> pageAdder,FuncNoArg<List<T>> dataGetter){
        List<T> list = new ArrayList<>();
        for(int i = 0;;){
            pageAdder.call(++i);
            List<T> result=dataGetter.invoke();
            if(esdk.obj.isEmpty(result)) break;
            list.addAll(result);
        }
        return list;
    }

    public static Object testobj(){
      System.out.println("只执行一次就是正确的");
      return "a";
    }

    public static void main(String[] args){
      esdk.tool.assertEquals(Stream.of("a", "a").filter(asPredicate(Objects::equals, testobj())).toList().toString(),"[a, a]");
        JSONObject jsonObject=new JSONObject();
        safeRun(()->jsonObject.clear(), false);
        safeRun(()->jsonObject.put("", ""), false);
      System.out.println("444444444444444"+Stream.of("aaaa","bbb","cc")
          .filter(esdk.func.asPredicate(e->{
              if(true)
                  throw new Exception("aaaaaaaaaaaaaaa");
          return e.length()>1;
        })).toArray());
    }
}
